import DexieCtx from '@/utils/dexiectx';
import Config from '@/utils/config';
import { Api, TelegramClient } from 'telegram'
import { StringSession } from 'telegram/sessions'
import Axios from 'axios';

class TonstationTgweb {
  constructor() {
  }

  async allRun() {
    this.dexie = await DexieCtx.db()
    const allAccounts = await this.dexie.accounts.where("session").notEqual("").toArray()
    const project = await this.dexie.projects.get({
      name: "tonstation"
    })
    // 用户没设置邀请url，则使用我们自己的邀请url
    let inviteList = project.inviteList ?? []
    if (inviteList.length == 0) {
      inviteList = ["https://t.me/tonstationgames_bot/app?startapp=ref_goif5bktdelydyur2wzl2d"];
    }
    let sepIndex = 0;
    const groupStep = 1
    const sleepNow = (delay) => new Promise((resolve) => setTimeout(resolve, delay))

    while (true) {
      if (sepIndex >= allAccounts.length) {
        break;
      }
      const start = sepIndex
      const end = Math.min(sepIndex + groupStep, allAccounts.length)
      const accountsGroup = allAccounts.slice(start, end)
      try {
        const allClients = accountsGroup.map(item => {
          const strSession = new StringSession(item.session)
          const client = new TelegramClient(strSession, Config.API_ID, Config.API_HASH, {
            connectionRetries: 3,
            useWSS: true,
            timeout: 20,
          })
          client.phone = item.phone
          return client
        })
        if (inviteList.length > 0) {
          for (let index = 0; index < allClients.length; index++) {
            const client = allClients[index];
            const realIndex = index + start
            const inviteUrl = inviteList[realIndex % inviteList.length]
            client.inviteUrl = inviteUrl
          }
        }

        const promiseGroup = allClients.map(client => {
          return this.run(client)
        })
        await Promise.allSettled(promiseGroup)
        console.log(Date() + "tonstation tgweb finished " + start + "~" + end)
      } catch (error) {
        console.error(error)
      } finally {
        sepIndex = end
      }
    }
  }

  random_str(length) {
    var str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    var result = '';
    for (var i = length; i > 0; --i)
      result += str[Math.floor(Math.random() * str.length)];
    return result;
  }

  getRandomIntInclusive(min, max) {
    const minCeiled = Math.ceil(min);
    const maxFloored = Math.floor(max);
    return Math.floor(Math.random() * (maxFloored - minCeiled + 1) + minCeiled); // 包含最小值和最大值
  }

  async run(client) {
    try {
      await client.connect();
      const isAuth = await client.checkAuthorization()
      if (isAuth != true) {
        throw new Error("unauth");
      }
      const user = await client.getInputEntity('tonstationgames_bot');
      const result = await client.invoke(
        new Api.messages.RequestWebView({
          peer: user,
          bot: "tonstationgames_bot",
          fromBotMenu: false,
          url: (client.inviteUrl || "https://t.me/tonstationgames_bot/app?startapp=ref_f3bxzmvvuiayrpdb27qbm2"),
          platform: "android"
        })
      );

      const url = result.url;
      console.log("tonstation", client.phone, url)
      await this.updateTonstationTable(client.phone, url)


      // Codes below are mored from tonstation.js, currently these code just could run at Browser
      let webSessionUrl = url

      if (webSessionUrl.startsWith("https://") == false) {
        // console.error(`${this.tokenInfo.phone}  error session url ${webSessionUrl}`);
        return
      }
      webSessionUrl = decodeURIComponent(webSessionUrl)
      let session = webSessionUrl.split("#tgWebAppData=")[1]
      session = session.split("&tgWebAppVersion")[0]

      // if ( session.indexOf('username') <= 0) { // At the first time, we need check if the user registed. If the URL value has not inclulded username value, it means the current account has not registed. Need register first. 
      let user_name = session.slice(session.indexOf('first_name') + 19, session.indexOf('last_name') - 9)
      user_name = user_name.replace(/[&\/\\#,+()$~%.'":*?<>{}]/g,'');
      user_name = user_name + this.random_str(8)

      // parse user_id
      const user_id = session.slice(session.indexOf('user=%7B%22id%22%3A') + 19, session.indexOf('%2C%22first_name'))

      const auth_token_payload = {
        'initData': session,
      }

      const req_header = {
        'content-type': 'application/json',
      }

      const axios = Axios.create({
        timeout: 90 * 1000,
      })

      // console.log(auth_token_payload)

      // Try to register, if already registed will got code 500 and an error message. But just ignore it currently.
      await axios.post('https://tonstation.app/userprofile/api/v1/users', auth_token_payload, {
        headers: {
          'content-type': 'application/json'
        },
      }).then(response => {
        // console.log(response)
      }).catch(function (error) {
        // console.log(error)
        // Try to register user firstly
      })

      let access_token = ''

      // Get user access token.
      await axios.post('https://tonstation.app/userprofile/api/v1/users/auth', auth_token_payload, {
        headers: {
          'content-type': 'application/json'
        },
      }).then(response => {
        access_token = response.data.accessToken
      }).catch(function (error) {
        // console.log(error)
        // Try to register user firstly
      })

      const authed_header = {
        authorization: "Bearer " + access_token,
        'Content-Type': 'application/json'
      }

      /* start works */
      /* 1. Daily Check in */
      const daily_checkin_payload = {
        "userId": user_id
      }

      await axios.post('https://tonstation.app/farming/api/v1/user-rates/login', daily_checkin_payload, {
        headers: authed_header
      }).then(response => {
        // console.log('login   ===============================  :::::: ')
        // console.log(response)
      }).catch(function (error) {
        // console.log(error)
      })

      let userAddress = ''
      let userBalance = ''
      /* 2. User Balance */
      await axios.get('https://tonstation.app/userprofile/api/v1/users/' + user_id + '/by-telegram-id', {
        headers: authed_header
      }).then(response => {
        // console.log('address info ===============================  :::::: ')
        // console.log(response)
        userAddress = response.data.address
      }).catch(function (error) {
        // console.log(error)
      })

      // console.log('userAddresss ...... ', userAddress)

      // console.log('authed_header ', authed_header)

      await axios.get('https://tonstation.app/balance/api/v1/balance/' + userAddress + '/by-address', {
        headers: authed_header
      }).then(response => {
        userBalance = response.data.data.balance
        // userBalance = response.data.balance
      }).catch(function (error) {
        // console.log(error)
      })

      /* 3. Boots */
      await axios.get('https://tonstation.app/farming/api/v1/boosts/' + user_id, {
        headers: authed_header
      }).then(response => {
        // console.log(response)
        // userBalance = response.data.balance
      }).catch(function (error) {
        // console.log(error)
      })

      /* 4. start farming */
      await axios.get('https://tonstation.app/farming/api/v1/tasks', {
        headers: authed_header
      }).then(response => {
        // console.log(response.data.data)
        response.data.data.forEach(function (taskKey, taskValue) {
          console.log("task id", taskKey.id)
          // start farming 
          axios.post('https://tonstation.app/farming/api/v1/farming/start', {
            "userId": user_id,
            "taskId": taskKey.id
          }, {
            headers: authed_header
          }).then(response1 => {
            // console.log(response1)

          }).catch(function (error1) {
            // console.log(error1)
          })
        })
        // userBalance = response.data.balance
      }).catch(function (error) {
        // console.log(error)
      })


      /* 5. try to end farming */
      await axios.get('https://tonstation.app/farming/api/v1/farming/' + user_id + '/running', {
        headers: authed_header
      }).then(response => {
        // console.log('framing.........................')
        // console.log(response.data.data)
        response.data.data.forEach(function (taskKey, taskValue) {
          console.log("- try to end tasks ")
          console.log("task id", taskKey._id)
          // try to end farming
          axios.post('https://tonstation.app/farming/api/v1/farming/claim', {
            "userId": user_id,
            "taskId": taskKey._id
          }, {
            headers: authed_header
          }).then(response2 => {
            // console.log(response2)

          }).catch(function (error2) {
            // console.log(error2)
          })

        })
        // userBalance = response.data.balance
      }).catch(function (error) {
        // console.log(error)
      })


      /* 6. fetch quests  */
      await axios.get('https://tonstation.app/quests/api/v1/quests?userId=' + user_id + '&size=50', {
        headers: authed_header
      }).then(response => {

        response.data.data.forEach(function (questKey, questValue) {
          const quest_body = {
            "project": questKey.project,
            "userId": user_id,
            "questId": questKey.id
          }
          // start quests 
          // console.log('start quests')
          axios.post('https://tonstation.app/quests/api/v1/start', quest_body, {
            headers: authed_header
          }).then(response2 => {
            // console.log(response2)
          }).catch(function (error2) {
            // console.log(error2)
          })

          // console.log('end quests')
          axios.post('https://tonstation.app/quests/api/v1/claim', quest_body, {
            headers: authed_header
          }).then(response3 => {
            // console.log(response3)
          }).catch(function (error3) {
            // console.log(error3)
          })
        })
        // userBalance = response.data.balance
      }).catch(function (error) {
        // console.log(error)
      })


      /* 6. fetch repeatable quests  */
      await axios.get('https://tonstation.app/quests/api/v1/repeatable-quests/' + user_id + '/quests', {
        headers: authed_header
      }).then(response => {
        // console.log("==================>>> fetch repeatable quests ------")
        // console.log(response.data.data)

        response.data.data.forEach(function (questKey, questValue) {
          // console.log(questKey)
          const app_id = questKey.appId

          const repeatable_quest_body = {
            "appId": app_id,
            "userId": user_id,
          }

          // start quests 
          axios.post('https://tonstation.app/quests/api/v1/repeatable-quests/' + user_id + '/' + app_id + '/start', repeatable_quest_body, {
            headers: authed_header
          }).then(response2 => {
          }).catch(function (error2) {
            // console.log(error2)
          })

          axios.post('https://tonstation.app/quests/api/v1/repeatable-quests/' + user_id + '/' + app_id + '/claim', repeatable_quest_body, {
            headers: authed_header
          }).then(response3 => {
          }).catch(function (error3) {
            // console.log(error3)
          })
        })
        // userBalance = response.data.balance
      }).catch(function (error) {
        // console.log(error)
      })

      let userBalance_final = 0

      const self = this
      /* 7. update user balance  */
      await axios.get('https://tonstation.app/balance/api/v1/balance/' + userAddress + '/by-address', {
        headers: authed_header
      }).then(response => {
        userBalance_final = response.data.data.balance[0].balance
        console.log('userBalance_final         : ', userBalance_final)
        // userBalance = response.data.balance
      }).catch(function (error) {
        // console.log(error)
      })

      const date = (new Date()).toLocaleString()
      
      if (userBalance_final > 0) {
        const oldValue = await this.dexie.tonstation.get({
          phone: client.phone
        })

        const new_count = (oldValue.count || 0) + 1
        await this.dexie.tonstation.where('phone').equals(client.phone).modify({
          score: userBalance_final,
          gameupdate: date,
          count: new_count,
        })
      }

    } catch (error) {
      console.error(client.phone, error)
      // if (error.message == 'unauth') {
      //   console.error(client.phone, "TG未登录")
      //   await dexie.tonstation.where('phone').equals(client.phone).delete()
      //   await dexie.accounts.where('phone').equals(client.phone).modify({
      //     session: null
      //   })
      // }
    } finally {
      try {
        await client.disconnect()
        await client.destroy()
      } catch (error) {
      }
    }

  }

  async updateTonstationTable(phone, tgweb) {
    const oldValue = await this.dexie.tonstation.get({
      phone: phone
    })
    const dateStr = (new Date()).toLocaleString()
    if (oldValue == null) {
      await this.dexie.tonstation.add({
        phone,
        tgweb: tgweb,
        tokenupdate: dateStr,
      })
    } else {
      await this.dexie.tonstation.where("phone").equals(phone).modify({
        tgweb: tgweb,
        tokenupdate: dateStr,
      })
    }
  }
}

export default TonstationTgweb